from moviepy.editor import ImageSequenceClip, concatenate_videoclips, AudioFileClip
from PIL import Image
import os
import logging
from typing import List

TARGET_SIZE = (1920, 1080)
FRAME_RATE = 24

def generate_video(timeline: List[dict], screenshot_dirs: List[str], output_path: str) -> None:
    try:
        clips = []
        processed_files = []

        # 遍历所有知识点帧目录
        for dir_idx, frames_dir in enumerate(screenshot_dirs):
            if not os.path.exists(frames_dir):
                raise FileNotFoundError(f"帧目录不存在: {frames_dir}")

            # 加载并预处理帧文件
            frame_files = sorted(
                [os.path.join(frames_dir, f) for f in os.listdir(frames_dir) if f.endswith('.png')],
                key=lambda x: int(os.path.splitext(x)[0].split('_')[-1])
            )

            if not frame_files:
                raise ValueError(f"空帧目录: {frames_dir}")

            # 尺寸标准化处理
            standardized_frames = []
            for frame_path in frame_files:
                try:
                    with Image.open(frame_path) as img:
                        if img.size != TARGET_SIZE:
                            # 生成临时标准化文件
                            temp_path = f"{frame_path}.temp.png"
                            img.resize(TARGET_SIZE).save(temp_path)
                            standardized_frames.append(temp_path)
                            processed_files.append(temp_path)
                        else:
                            standardized_frames.append(frame_path)
                except Exception as e:
                    logging.error(f"帧处理失败: {frame_path} - {str(e)}")
                    continue

            # 按知识点分段处理
            for seg_idx, segment in enumerate(timeline):
                start_frame = seg_idx * 24
                end_frame = start_frame + 24
                segment_frames = standardized_frames[start_frame:end_frame]

                if not segment_frames:
                    logging.warning(f"缺失知识点片段: 目录{dir_idx} 知识点{seg_idx}")
                    continue

                # 创建动画片段 (24帧=1秒)
                animation_clip = ImageSequenceClip(segment_frames, fps=FRAME_RATE)
                
                # 计算等待时间（总时长 - 动画时长）
                total_duration = segment['end'] - segment['start']
                wait_duration = max(0, total_duration - 1.0)  # 减去1秒动画时间
                
                if wait_duration > 0:
                    # 创建等待片段（延长最后一帧）
                    last_frame_clip = ImageSequenceClip([segment_frames[-1]], fps=FRAME_RATE).set_duration(wait_duration)
                    clips.extend([animation_clip, last_frame_clip])
                else:
                    clips.append(animation_clip)

        # 合成最终视频
        final_clip = concatenate_videoclips(clips)
        
        # 音频集成（需提前生成音频文件）
        if os.path.exists('output/audio/full_audio.mp3'):
            audio_clip = AudioFileClip('output/audio/full_audio.mp3')
            final_clip = final_clip.set_audio(audio_clip)
        
        # 输出浏览器兼容格式
        final_clip.write_videofile(
            output_path,
            codec="libx264",
            fps=FRAME_RATE,
            preset="medium",
            ffmpeg_params=[
                "-pix_fmt", "yuv420p",
                "-profile:v", "baseline"
            ]
        )

    except Exception as e:
        logging.error(f"视频生成失败: {str(e)}")
        raise
    finally:
        # 资源清理
        if 'final_clip' in locals():
            final_clip.close()
        for f in processed_files:
            if os.path.exists(f):
                os.remove(f)

# 辅助函数：加载并排序帧文件
def load_sorted_frames(frames_dir: str) -> List[str]:
    """
    加载并排序指定目录中的帧文件
    Args:
        frames_dir: 包含帧图片的目录路径
    Returns:
        按序号排序的帧文件名列表
    """
    return sorted(
        [f for f in os.listdir(frames_dir) if f.endswith('.png')],
        key=lambda x: int(x.split('_')[1].split('.')[0])
    )